package archer.application.manager.filter;

import archer.framework.protocol.exception.BusinessException;
import archer.framework.protocol.result.ResultCode;
import archer.framework.utils.ServletUtils;
import archer.framework.utils.ValidateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import java.io.IOException;

/**
 * 登录或权限相关的异常处理过滤器
 * 其它在到达spring的DispatcherServlet之前就抛出的异常都可以在这里捕获到做统一处理
 *
 * @author kent
 * @date 16/6/30.
 */
public class ExceptionFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionFilter.class);

    private static final String DEFAULT_LOGOUT_URL = "/logout";

    // 退出登录url
    private String logoutUrl;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String url = filterConfig.getInitParameter("logoutUrl");
        logoutUrl = ValidateUtils.isEmpty(url) ? DEFAULT_LOGOUT_URL : url;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        try {

            filterChain.doFilter(servletRequest, servletResponse);

        } catch (Exception e) {

            logException(e);

            if (isNotLoginedException(e)) {
                ServletUtils.redirect(servletRequest, servletResponse, logoutUrl);
                return;
            }

            throw new RuntimeException(e);
        }
    }

    @Override
    public void destroy() {

    }

    //------------------------------------ private ----------------------------------------

    /**
     * @param e
     * @return
     */
    private boolean isNotLoginedException(Exception e) {

        if (e instanceof BusinessException) {
            return ResultCode.NOT_LOGINED.name().equals(businessException(e).getResultCode());
        }

        return e.getCause() instanceof BusinessException && ResultCode.NOT_LOGINED.name().equals(businessException(e.getCause()).getResultCode());
    }

    private BusinessException businessException(Throwable exception) {
        return (BusinessException) exception;
    }

    private void logException(Exception e) {

        LOGGER.info(">>>>>>>>>>>>>>>>>>>>>>catch exception in ExceptionFilter", e);
    }
}
